﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace XTYAPI.PLC
{
  public  class PIDController
    {
        /// <summary>
        /// 比例系数，用于控制输出量与误差的比例关系  
        /// </summary>
        public double Kp { get; set; } = 10;
        /// <summary>
        /// 积分系数，用于控制输出量与误差的积分关系
        /// </summary>
        public double Ki { get; set; } = 20;
        /// <summary>
        /// 微分系数，用于控制输出量与误差的微分关系  
        /// </summary>
        private double Kd { get; set; } = 0;
        /// <summary>
        /// 上一次误差值，用于计算微分值  
        /// </summary>
        private double previousError;
        /// <summary>
        /// 积分值，用于计算输出量  
        /// </summary>
        private double integral;
        /// <summary>
        /// 微分值，用于计算输出量  
        /// </summary>
        private double derivative;
        /// <summary>
        /// PIDController构造函数，用于初始化PID控制器对象，并设置比例、积分和微分系数
        /// </summary>
        /// <param name="kp"></param>
        /// <param name="ki"></param>
        /// <param name="kd"></param>
        public PIDController(double kp, double ki, double kd)
        {
            this.Kp = kp;
            this.Ki = ki;
            this.Kd = kd;
            this.previousError = 0;  // 将上一次误差值初始化为0  
            this.integral = 0;  // 将积分值初始化为0  
            this.derivative = 0;  // 将微分值初始化为0  
        }
        /// <summary>
        /// PID计算,若取消积分作用积分可以设置为0
        /// </summary>
        /// <param name="setpoint">设定值</param>
        /// <param name="actualValue">当前值</param>
        /// <param name="dt">时间间隔</param>
        /// <returns></returns>
        public double Calculate(double setpoint, double actualValue, double dt=1)
        {
            // 计算误差，即设定值与实际值的差值  
            double error = setpoint - actualValue;
            // 将误差加入积分值中，计算积分值  
            integral += error * dt;
            // 计算微分值，即误差的变化率  
            derivative = (error - previousError) / dt;
            // 根据比例、积分和微分系数计算输出值  
            double output = Kp * error + Ki * integral + Kd * derivative;
            // 将当前误差值存储在previousError属性中，以便下一次计算使用  
            previousError = error;
            // 返回计算结果作为输出值  
            return output;
        }
    }
}
